package com.example.lt.service.user.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.lt.authority.AuthorityUtils;
import com.example.lt.entity.user.*;
import com.example.lt.mapper.user.PermissionMapper;
import com.example.lt.service.user.PermissionService;
import com.example.lt.service.user.RolePermissionService;
import com.example.lt.service.user.UserRoleService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author 小涛Tao
 * @Date: 2024/08/16/18:40
 * version 1.0 注释：
 **/
@Service
@RequiredArgsConstructor
public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permission> implements PermissionService {

    private final RolePermissionService rolePermissionService;

    private final UserRoleService userRoleService;

    // Permission比较器
    private  class PermissionComparator implements Comparator<Permission> {
        @Override
        public int compare(Permission o1, Permission o2) {
            return -o1.getSort()-o2.getSort();
        }
    }

    /**
     * 初始化菜单
     * @param userId 用户id
     * @return
     */
    @Override
    public Map<String, Object> initMenu(Long userId) {
        // 创建返回结果 Map集合
        Map<String, Object> data = new HashMap<>();
        List<Menu> menus = new ArrayList<>();
        List<Menu> parentMenus = new ArrayList<>();

        // 封装用户的权限集合
        Set<String> set = new HashSet<>();

        // 根据当前用户获取菜单

        // 根据用户id查询对应的角色id
        final List<Long> roleIds = userRoleService.list(new LambdaQueryWrapper<UserRole>().eq(UserRole::getUserId, userId).select(UserRole::getRoleId))
                .stream().map(UserRole::getRoleId).collect(Collectors.toList());

        if (ObjectUtils.isEmpty(roleIds)) {
            return Collections.EMPTY_MAP;
        }

        // 根据角色id获取对应的权限id
        final List<Integer> permissionIds = rolePermissionService.list(new LambdaQueryWrapper<RolePermission>().in(RolePermission::getRoleId, roleIds).select(RolePermission::getPermissionId))
                .stream().map(RolePermission::getPermissionId).collect(Collectors.toList());

        // 根据权限id查出权限
        // 查出所有权限-->转成对应的菜单对象
        list(new LambdaQueryWrapper<Permission>().in(Permission::getId, permissionIds))
                .stream()
                .sorted(new PermissionComparator())
                .forEach(permission -> {
                    Menu menu = new Menu();
                    BeanUtils.copyProperties(permission, menu);
                    menu.setTitle(permission.getName());
                    menus.add(menu);
                });

        // list转树形结构
        // 1. 先找到根节点
        for (Menu menu : menus) {
            if (menu.getPId().compareTo(0L) == 0 && menu.getIsMenu() != 1) {
                menu.setChild(new ArrayList<Menu>());
                parentMenus.add(menu);
            }
        }

        // 2. 根据根节点找到子节点
        for (Menu menu : parentMenus) {
            menu.getChild().add(findChild(menu,menus,set));
        }

        // 保存用户权限
        AuthorityUtils.setAuthority(userId, set);

        MenuKey menuKey1 = new MenuKey();
        MenuKey menuKey2 = new MenuKey();
        menuKey1.setTitle("首页");
        menuKey1.setHref("page/welcome.html?t=1");
        menuKey2.setTitle("悦动瞬间");
        menuKey2.setHref("/index.html");
        data.put("menuInfo",parentMenus);
        data.put("homeInfo",menuKey1);
        data.put("logoInfo",menuKey2);
        return data;
    }

    @Override
    public List<Permission> treeSelect() {
        // 1、创建返回结果
        List<Permission> data = new ArrayList<>();
        // 2、查询出所有权限，除了按钮
        List<Permission> permissions = list(new LambdaQueryWrapper<Permission>().ne(Permission::getId, 1));
        // 3、找到根节点
        for (Permission permission : permissions) {
            if (permission.getId().compareTo(0L) == 0) {
                permission.setChildren(new ArrayList<Permission>());
                data.add(permission);
            }
        }

        for (Permission datum : data) {
            // TODO 需要测试这样子递归会不会有问题
            datum.getChildren().add(findTreeSelectChildren(datum,permissions));
        }
        return data;
    }

    @Override
    @Transactional
    public void removeMenu(Long id) {
        List<Long> ids = new ArrayList<>();
        findPermissionId(id, ids);
        ids.add(id);
        removeByIds(ids);
        rolePermissionService.remove(new LambdaQueryWrapper<RolePermission>().in(RolePermission::getPermissionId,ids));
    }

    private void findPermissionId(Long id, List<Long> ids) {
        list(new LambdaQueryWrapper<Permission>().eq(Permission::getPId, id).select(Permission::getId))
                .stream()
                .forEach(permission -> {
                    ids.add(permission.getId());
                    findPermissionId(permission.getId(), ids);
                });
    }

    private Permission findTreeSelectChildren(Permission datum, List<Permission> permissions) {
        datum.setChildren(new ArrayList<Permission>());

        for (Permission permission : permissions) {
            if (datum.getId().compareTo(permission.getPId()) == 0) {
                datum.getChildren().add(findTreeSelectChildren(permission, permissions));
            }
        }
        return datum;
    }


    /**
     * 找子节点
     * @param menu 节点
     * @param menus 所有节点集合
     * @param set 权限集合
     * @return
     */
    private Menu findChild(Menu menu, List<Menu> menus, Set<String> set) {
        menu.setChild(new ArrayList<Menu>());
        for (Menu m : menus) {
            if (!ObjectUtils.isEmpty(m.getPath())){
                set.add(m.getPath());
            }
            if (m.getIsMenu()!=1){
                if (menu.getId().compareTo(m.getPId()) ==0 ) {
                    // 递归调用该方法
                    menu.getChild().add(findChild(m,menus,set));
                }
            }
        }
        return menu;
    }

}
